using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Windows;
using System.Windows.Markup;

namespace Infralution.Localization.Wpf
{
	/// <summary>
	/// Defines a base class for markup extensions which are managed by a central 
	/// <see cref="T:Infralution.Localization.Wpf.MarkupExtensionManager" />.   This allows the associated markup targets to be
	/// updated via the manager.
	/// </summary>
	/// <remarks>
	/// The ManagedMarkupExtension holds a weak reference to the target object to allow it to update 
	/// the target.  A weak reference is used to avoid a circular dependency which would prevent the
	/// target being garbage collected.  
	/// </remarks>
	public abstract class ManagedMarkupExtension : MarkupExtension
	{
		private List<WeakReference> list_0 = new List<WeakReference>();

		private object object_0;

		/// <summary>
		/// Is an associated target still alive ie not garbage collected
		/// </summary>
		public bool IsTargetAlive
		{
			get
			{
				if (list_0.Count == 0)
				{
					return true;
				}
				foreach (WeakReference item in list_0)
				{
					if (item.IsAlive)
					{
						return true;
					}
				}
				return false;
			}
		}

		/// <summary>
		/// Returns true if a target attached to this extension is in design mode
		/// </summary>
		public bool IsInDesignMode
		{
			get
			{
				foreach (WeakReference item in list_0)
				{
					DependencyObject dependencyObject = item.Target as DependencyObject;
					if (dependencyObject != null && DesignerProperties.GetIsInDesignMode(dependencyObject))
					{
						return true;
					}
				}
				return false;
			}
		}

		/// <summary>
		/// Return the target objects the extension is associated with
		/// </summary>
		/// <remarks>
		/// For normal elements their will be a single target.   For templates
		/// their may be zero or more targets
		/// </remarks>
		protected List<WeakReference> TargetObjects => list_0;

		/// <summary>
		/// Return the Target Property the extension is associated with
		/// </summary>
		/// <remarks>
		/// Can either be a <see cref="T:System.Windows.DependencyProperty" /> or <see cref="T:System.Reflection.PropertyInfo" />
		/// </remarks>
		protected object TargetProperty => object_0;

		/// <summary>
		/// Return the type of the Target Property
		/// </summary>
		protected Type TargetPropertyType
		{
			get
			{
				Type result = null;
				if (object_0 is DependencyProperty)
				{
					result = (object_0 as DependencyProperty).PropertyType;
				}
				else if (object_0 is PropertyInfo)
				{
					result = (object_0 as PropertyInfo).PropertyType;
				}
				else if (object_0 != null)
				{
					result = object_0.GetType();
				}
				return result;
			}
		}

		/// <summary>
		/// Create a new instance of the markup extension
		/// </summary>
		public ManagedMarkupExtension(MarkupExtensionManager manager)
		{
			manager.method_0(this);
		}

		/// <summary>
		/// Return the value for this instance of the Markup Extension
		/// </summary>
		/// <param name="serviceProvider">The service provider</param>
		/// <returns>The value of the element</returns>
		public override object ProvideValue(IServiceProvider serviceProvider)
		{
			RegisterTarget(serviceProvider);
			object result = this;
			if (object_0 != null)
			{
				result = GetValue();
			}
			return result;
		}

		/// <summary>
		/// Called by <see cref="M:Infralution.Localization.Wpf.ManagedMarkupExtension.ProvideValue(System.IServiceProvider)" /> to register the target and object
		/// using the extension.   
		/// </summary>
		/// <param name="serviceProvider">The service provider</param>
		protected virtual void RegisterTarget(IServiceProvider serviceProvider)
		{
			IProvideValueTarget provideValueTarget = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
			object targetObject = provideValueTarget.TargetObject;
			if (targetObject != null && targetObject.GetType().FullName != "System.Windows.SharedDp")
			{
				object_0 = provideValueTarget.TargetProperty;
				list_0.Add(new WeakReference(targetObject));
			}
		}

		/// <summary>
		/// Called by <see cref="M:Infralution.Localization.Wpf.ManagedMarkupExtension.UpdateTargets" /> to update each target referenced by the extension
		/// </summary>
		/// <param name="target">The target to update</param>
		protected virtual void UpdateTarget(object target)
		{
			if (object_0 is DependencyProperty)
			{
				(target as DependencyObject)?.SetValue(object_0 as DependencyProperty, GetValue());
			}
			else if (object_0 is PropertyInfo)
			{
				try
				{
					(object_0 as PropertyInfo).SetValue(target, GetValue(), null);
				}
				catch
				{
				}
			}
		}

		/// <summary>
		/// Update the associated targets
		/// </summary>
		public void UpdateTargets()
		{
			foreach (WeakReference item in list_0)
			{
				if (item.IsAlive)
				{
					UpdateTarget(item.Target);
				}
			}
		}

		/// <summary>
		/// Is the given object the target for the extension 
		/// </summary>
		/// <param name="target">The target to check</param>
		/// <returns>True if the object is one of the targets for this extension</returns>
		public bool IsTarget(object target)
		{
			foreach (WeakReference item in list_0)
			{
				if (item.IsAlive && item.Target == target)
				{
					return true;
				}
			}
			return false;
		}

		/// <summary>
		/// Return the value associated with the key from the resource manager
		/// </summary>
		/// <returns>The value from the resources if possible otherwise the default value</returns>
		protected abstract object GetValue();
	}
}
